package ae.pcfc.cldos.online.common.clddb.dao.provider;

import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import ae.pcfc.cldos.online.common.clddb.dao.MessageInboxDAO;
import ae.pcfc.cldos.online.common.clddb.domain.AppMetaData;
import ae.pcfc.cldos.online.common.clddb.domain.MessageInbox;
import ae.pcfc.cldos.online.common.clddb.domain.TaskMaster;
import ae.pcfc.cldos.online.common.dao.GenericDAO;
import ae.pcfc.cldos.online.common.util.UtilCommon;
import ae.pcfc.cldos.online.common.vo.UserInformationVO;
import ae.pcfc.cldos.online.common.vo.notifications.NotificationsDbRestrictionsVO;
import ae.pcfc.cldos.online.common.vo.tasks.TaskRequestDbRestrictions;

/**
 * 
 * @author arosa
 *
 */
@Repository
public class MessageInboxDAOImpl extends GenericDAO implements MessageInboxDAO{

	private static final String __APP_META_DATA_ALIAS = "appMetaDataAlias";
	
	private static final String __APP_META_DATA_CLIENT_ID = __APP_META_DATA_ALIAS+"."+AppMetaData.__CLIENT_ID;
	//private static final String __APP_META_DATA_ID = __APP_META_DATA_ALIAS+"."+AppMetaData.__ID;
	private static final String __APP_META_DATA_REF_NO = __APP_META_DATA_ALIAS+"."+AppMetaData.__CLIENT_REF_NO;
	private static final String __APP_META_DATA_SERVICE_CODE = __APP_META_DATA_ALIAS+"."+AppMetaData.__SERVICE_CODE;
	private static final String __APP_META_DATA_SERVICE_MASTER = __APP_META_DATA_ALIAS+"."+AppMetaData.__SERVICE_MASTER;
	private static final String __APP_META_DATA_STATUS = __APP_META_DATA_ALIAS+"."+AppMetaData.__APPLICATION_STATUS;
	private static final String __APP_META_DATA_STATUS_CODE = __APP_META_DATA_ALIAS+"."+AppMetaData.__APPLICATION_STATUS_CODE;
	
	private static final String __TASK_MASTER_ALIAS = "taskMasterAlias";
	private static final String __TASK_MASTER_TYPE = __TASK_MASTER_ALIAS+"."+TaskMaster.__TASK_TYPE;
	
	public void add(MessageInbox messageInbox) {
		saveOrUpdate(messageInbox);
	}
	
	public void update(MessageInbox messageInbox) {
		saveOrUpdate(messageInbox);
	}
	
	private DetachedCriteria getTasksCriteria(UserInformationVO userInformationVO, TaskRequestDbRestrictions taskRequestDbRestrictions){
		DetachedCriteria criteria = DetachedCriteria.forClass(MessageInbox.class);
		criteria.createAlias(MessageInbox.APP_META_DATA, __APP_META_DATA_ALIAS, Criteria.INNER_JOIN);
		criteria.setFetchMode(MessageInbox.APP_META_DATA, FetchMode.JOIN);
	
		criteria.add(Restrictions.eq(MessageInbox.ACTION_FLAG, MessageInbox.MESSAGE_ACTION_FLAG_NOT_DONE));
		criteria.add(Restrictions.eq(MessageInbox.MESSAGE_TYPE, MessageInbox.MESSAGE_TYPE_TASK));
		
		criteria.createAlias(MessageInbox.__TASK_MASTER, __TASK_MASTER_ALIAS, Criteria.INNER_JOIN);
		criteria.setFetchMode(MessageInbox.__TASK_MASTER, FetchMode.JOIN);
		
		Date dateFrom = null;
		Date dateTo = null;
		if(taskRequestDbRestrictions.getDateFrom() != null ) 
			dateFrom = UtilCommon.getDateFromString(taskRequestDbRestrictions.getDateFrom()) ;
		if(taskRequestDbRestrictions.getDateTo() != null )
			dateTo = UtilCommon.getDateFromString(taskRequestDbRestrictions.getDateTo());
	
		
		if(dateFrom!=null && dateTo!=null && dateFrom.compareTo(dateTo)<=0){
			criteria.add(Restrictions.between(MessageInbox.__MESSAGE_SEND_ON, dateFrom, dateTo));
		} else if(dateFrom!=null){
			criteria.add(Restrictions.ge(MessageInbox.__MESSAGE_SEND_ON, dateFrom));
		} else if(dateTo!=null){
			criteria.add(Restrictions.le(MessageInbox.__MESSAGE_SEND_ON, dateTo));
		}
			
		String refNo = taskRequestDbRestrictions.getRefNo();
		if(refNo!=null && !refNo.isEmpty()){
			criteria.add(Restrictions.eq(__APP_META_DATA_REF_NO, refNo));
		}
	
		Long serviceCode = taskRequestDbRestrictions.getServiceId();
		if(serviceCode!=null){
			criteria.add(Restrictions.eq(__APP_META_DATA_SERVICE_CODE, serviceCode));
		}
		criteria.add(Restrictions.eq(__APP_META_DATA_CLIENT_ID, userInformationVO.getClientId()));
		
		if(!userInformationVO.isAdmin()){
			criteria.add(Restrictions.ne(__TASK_MASTER_TYPE, MessageInbox.__TASK_TYPE_ADMIN).ignoreCase());
		}
		
		Long taskCode = taskRequestDbRestrictions.getTaskId();
		if(taskCode!=null){
			criteria.add(Restrictions.eq(MessageInbox.__TASK_CODE, taskCode));
		}
		
		Long statusId = taskRequestDbRestrictions.getStatusId();
		if(statusId!=null){
			criteria.add(Restrictions.eq(__APP_META_DATA_STATUS_CODE, statusId));
		}
		
		criteria.addOrder(Order.desc(MessageInbox.__MESSAGE_SEND_ON));
		criteria.addOrder(Order.desc(MessageInbox.__ID));
		return criteria;
	}
	
	@SuppressWarnings("unchecked")
	public List<MessageInbox> getUserTasks(UserInformationVO userInformationVO, TaskRequestDbRestrictions taskRequestDbRestrictions){
		
		DetachedCriteria criteria = getTasksCriteria(userInformationVO, taskRequestDbRestrictions);
		
		criteria.createAlias(__APP_META_DATA_SERVICE_MASTER, __APP_META_DATA_SERVICE_MASTER, Criteria.INNER_JOIN);
		criteria.setFetchMode(__APP_META_DATA_SERVICE_MASTER, FetchMode.JOIN);
		
		criteria.createAlias(__APP_META_DATA_STATUS, __APP_META_DATA_STATUS, Criteria.INNER_JOIN);
		criteria.setFetchMode(__APP_META_DATA_STATUS, FetchMode.JOIN);
		
		Integer currentPage = taskRequestDbRestrictions.getCuurentPage();
		Integer perPage = taskRequestDbRestrictions.getRowsPerPage();
		
		return (List<MessageInbox>)getListByCriteria(criteria, (currentPage-1)*perPage, perPage);
	}
	
	public Integer getTasksCount(UserInformationVO userInformationVO, TaskRequestDbRestrictions taskRequestDbRestrictions){
		return getTotal(getTasksCriteria(userInformationVO, taskRequestDbRestrictions));
	}
	
	@SuppressWarnings("unchecked")
	public List<MessageInbox> getUserNotifications(UserInformationVO userInformationVO, 
			NotificationsDbRestrictionsVO notificationsDbRestrictionsVO){
		
		DetachedCriteria criteria = getNotificationsCriteria(userInformationVO, notificationsDbRestrictionsVO);
		
		criteria.createAlias(__APP_META_DATA_SERVICE_MASTER, __APP_META_DATA_SERVICE_MASTER, Criteria.INNER_JOIN);
		criteria.setFetchMode(__APP_META_DATA_SERVICE_MASTER, FetchMode.JOIN);
		criteria.setFetchMode(MessageInbox.__APPLICATION_ATTACHMENTS, FetchMode.JOIN);
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);// <----- THIS HELP WITH DUBLICATE PARRENT ENTITY
		
		Integer currentPage = notificationsDbRestrictionsVO.getCuurentPage();
		Integer perPage = notificationsDbRestrictionsVO.getRowsPerPage();
		List<MessageInbox> result = (List<MessageInbox>)getListByCriteria(criteria, (currentPage-1)*perPage, perPage);
		return result;
	}
	
	private DetachedCriteria getNotificationsCriteria(UserInformationVO userInformationVO, 
			NotificationsDbRestrictionsVO notificationsDbRestrictionsVO){
		DetachedCriteria criteria = DetachedCriteria.forClass(MessageInbox.class);
		criteria.createAlias(MessageInbox.APP_META_DATA, __APP_META_DATA_ALIAS);
		criteria.setFetchMode(MessageInbox.APP_META_DATA, FetchMode.JOIN);
		criteria.add(Restrictions.eq(__APP_META_DATA_CLIENT_ID, userInformationVO.getClientId()));
		if(!notificationsDbRestrictionsVO.isDisplayReaded()){
			criteria.add(Restrictions.eq(MessageInbox.ACTION_FLAG, MessageInbox.MESSAGE_ACTION_FLAG_NOT_DONE));
		}
		criteria.add(Restrictions.eq(MessageInbox.MESSAGE_TYPE, MessageInbox.MESSAGE_TYPE_NOTIFICATION));
		
		String refNo = notificationsDbRestrictionsVO.getRefNo();
		if(refNo!=null && !refNo.isEmpty()){
			criteria.add(Restrictions.eq(__APP_META_DATA_REF_NO, refNo));
		}
	
		Long serviceCode = notificationsDbRestrictionsVO.getServiceId();
		if(serviceCode!=null){
			criteria.add(Restrictions.eq(__APP_META_DATA_SERVICE_CODE, serviceCode));
		}
		
		Long mesId = notificationsDbRestrictionsVO.getMesId();
		if(mesId!=null){
			criteria.add(Restrictions.idEq(mesId));
		}
		criteria.addOrder(Order.desc(MessageInbox.__ID));
		criteria.addOrder(Order.desc(MessageInbox.__MESSAGE_SEND_ON));
		return criteria;
	}
	
	public Integer getTotalNotifications(UserInformationVO userInformationVO, 
			NotificationsDbRestrictionsVO notificationsDbRestrictionsVO){
		return (Integer)getTotal(getNotificationsCriteria(userInformationVO, notificationsDbRestrictionsVO));
	}
	
	@SuppressWarnings("unchecked")
	public List<MessageInbox> getUncomplitedTaskByAppId(Long appId){
		DetachedCriteria criteria = DetachedCriteria.forClass(MessageInbox.class);
		criteria.add(Restrictions.eq(MessageInbox.__APP_ID, appId));
		criteria.add(Restrictions.eq(MessageInbox.ACTION_FLAG, MessageInbox.MESSAGE_ACTION_FLAG_NOT_DONE));
		return (List<MessageInbox>)getListByCriteria(criteria);
	}
	
	@SuppressWarnings("unchecked")
	public void completeAllApplicationTasks(Long appId){
		DetachedCriteria criteria = DetachedCriteria.forClass(MessageInbox.class);
		criteria.add(Restrictions.eq(MessageInbox.__APP_ID, appId));
		criteria.add(Restrictions.eq(MessageInbox.ACTION_FLAG, MessageInbox.MESSAGE_ACTION_FLAG_NOT_DONE));
	    for(MessageInbox messageInbox : (List<MessageInbox>)getListByCriteria(criteria)){
	    	messageInbox.setMiActionFlag(MessageInbox.MESSAGE_ACTION_FLAG_DONE);
	    	saveOrUpdate(messageInbox);
	    }
	}
	/**
	 * @param appId
	 * @return MessageInbox
	 */
	public MessageInbox getNotificationDetail(Long msgId){
		DetachedCriteria criteria = DetachedCriteria.forClass(MessageInbox.class);
		criteria.createAlias(MessageInbox.APP_META_DATA, __APP_META_DATA_ALIAS);
		criteria.setFetchMode(MessageInbox.APP_META_DATA, FetchMode.JOIN);
		criteria.add(Restrictions.eq(MessageInbox.MESSAGE_TYPE, MessageInbox.MESSAGE_TYPE_NOTIFICATION));
		criteria.add(Restrictions.idEq(msgId));
		criteria.setFetchMode(MessageInbox.__APPLICATION_ATTACHMENTS, FetchMode.JOIN);
		return findByCriteria(criteria);
	}
	
	public Integer getNewNotificationsCount(UserInformationVO userInformationVO){
		DetachedCriteria criteria = DetachedCriteria.forClass(MessageInbox.class);
		criteria.createAlias(MessageInbox.APP_META_DATA, __APP_META_DATA_ALIAS);
		criteria.setFetchMode(MessageInbox.APP_META_DATA, FetchMode.JOIN);
		criteria.add(Restrictions.eq(__APP_META_DATA_CLIENT_ID, userInformationVO.getClientId()));
		criteria.add(Restrictions.eq(MessageInbox.ACTION_FLAG, MessageInbox.MESSAGE_ACTION_FLAG_NOT_DONE));
		criteria.add(Restrictions.eq(MessageInbox.MESSAGE_TYPE, MessageInbox.MESSAGE_TYPE_NOTIFICATION));
		
		return getTotal(criteria); 
	}
	
	public Integer getNewTaskCount(UserInformationVO userInformationVO){
		DetachedCriteria criteria = DetachedCriteria.forClass(MessageInbox.class);
		criteria.createAlias(MessageInbox.APP_META_DATA, __APP_META_DATA_ALIAS, Criteria.INNER_JOIN);
		criteria.setFetchMode(MessageInbox.APP_META_DATA, FetchMode.JOIN);
	
		criteria.add(Restrictions.eq(MessageInbox.ACTION_FLAG, MessageInbox.MESSAGE_ACTION_FLAG_NOT_DONE));
		criteria.add(Restrictions.eq(MessageInbox.MESSAGE_TYPE, MessageInbox.MESSAGE_TYPE_TASK));
		
		criteria.createAlias(MessageInbox.__TASK_MASTER, __TASK_MASTER_ALIAS, Criteria.INNER_JOIN);
		criteria.setFetchMode(MessageInbox.__TASK_MASTER, FetchMode.JOIN);
		
		if(!userInformationVO.isAdmin()){
			criteria.add(Restrictions.ne(__TASK_MASTER_TYPE, MessageInbox.__TASK_TYPE_ADMIN).ignoreCase());
		}
		criteria.add(Restrictions.eq(__APP_META_DATA_CLIENT_ID, userInformationVO.getClientId()));
		
		return getTotal(criteria);
	}
	
	public void markNotificationAsReaded(Long mesId, UserInformationVO userInformationVO){
		DetachedCriteria criteria = DetachedCriteria.forClass(MessageInbox.class);
		criteria.createAlias(MessageInbox.APP_META_DATA, __APP_META_DATA_ALIAS);
		criteria.setFetchMode(MessageInbox.APP_META_DATA, FetchMode.JOIN);
		criteria.add(Restrictions.eq(__APP_META_DATA_CLIENT_ID, userInformationVO.getClientId()));
		criteria.add(Restrictions.idEq(mesId));
		criteria.add(Restrictions.eq(MessageInbox.ACTION_FLAG, MessageInbox.MESSAGE_ACTION_FLAG_NOT_DONE));
		criteria.add(Restrictions.eq(MessageInbox.MESSAGE_TYPE, MessageInbox.MESSAGE_TYPE_NOTIFICATION));
		
		MessageInbox messageInbox = findByCriteria(criteria);
		if(messageInbox!=null){
			messageInbox.setMiActionFlag(MessageInbox.MESSAGE_ACTION_FLAG_DONE);
			saveOrUpdate(messageInbox);
		}
	}

}
